import { Injectable } from '@nestjs/common';
import { MikroORM } from '@mikro-orm/core';
import { EntityManager, EntityRepository } from '@mikro-orm/mysql';
//import { TypechoContents } from './entities/typecho/TypechoContents';
// import { InjectRepository } from '@mikro-orm/nestjs';

import { Client, Credential, Error, Function, Packet, Payload, Subscription, Topic, onAck, onAuthenticate, onAuthorizePublish, onAuthorizeSubscribe, onClient, onClientDisconnect, onClientError, onClientReady, onClosed, onConnackSent, onConnectionError, onKeepLiveTimeout, onPreConnect, onPublish, onSubscribe, onUnsubscribe } from './modules/pigeon/pigeon.decorator';
import { PigeonService } from './modules/pigeon';

import AedesPacket from 'aedes-packet';
import { InjectQueue, Process, Processor } from '@nestjs/bull';
import { Job, Queue } from 'bull';
import { PublishPacket } from 'aedes';


//* Aedes NPM 官网文档:
//* https://www.npmjs.com/package/aedes
//* https://github.com/moscajs/aedes

//* 示例文档
//* https://github.com/moscajs/aedes/blob/HEAD/docs/Examples.md

//* 事件接口-文档链接
// https://www.npmjs.com/package/pigeon-mqtt-nest#handlers


@Processor('mqtt')
@Injectable()
export class AppService {
  constructor(
        // private readonly orm: MikroORM,
    // private readonly em: EntityManager,
    // @InjectRepository(TypechoContents)
    // private readonly typechoRepository: EntityRepository<TypechoContents>
    private readonly pigeonService : PigeonService,
    @InjectQueue('mqtt') private queue : Queue
  )
  {

  }

  async getHello(): Promise<string> {
    //const one = await this.em.find(TypechoContents,{});
    //const content : Object = await this.em.qb(TypechoContents).where({cid:7}).execute('get',true);
    //const text = JSON.stringify(content);
    return '';
  }

  @onPreConnect()
  onPreConnect(@Client() client, @Packet() packet, @Function() done) {
    console.log("Function: @onPreConnect()");
    return done(null, true);
  }

  @onAuthenticate()
  onAuthenticate(@Client() client, @Credential() credential, @Function() done) {
    console.log("Function: @onAuthenticate()");
    client.credential = credential;
    return done(null, true);
  }

  @onAuthorizePublish()
  onAuthorizePublish(@Client() client, @Packet() packet, @Function() done) {
    // this.queue.add(packet,{
    //   removeOnComplete:true,
    //   delay: 3000
    // });

    //console.log(packet.payload.toString())
    console.log("Function: @onAuthorizePublish()");
    //this.service.broker.publish()
    
    if (packet.topic === 'aaaa') {
      return done('wrong topic')
    }
    if (packet.topic === 'bbb') {
      packet.payload = Buffer.from('overwrite packet payload')
    }
    return done(null);
  }

  //* 默认情况下,authorizePublish 抛出异常来防止客户端发布以$SYS/前缀的主题可能带来的DoS攻击(#597)。
  //* 如果你实现自己的authorizePublish,建议你要加以检查。以下是默认实现。
  // *
  
  // @onAuthorizePublish()
  // onAuthorizePublish(@Client() client, @Packet() packet, @Function() done) {
  //   if (packet.topic.startsWith($SYS_PREFIX)) {
  //     return done(new Error($SYS_PREFIX + ' topic is reserved'))
  //   }
  //   return done(null);
  // }

  @onAuthorizeSubscribe()
  onAuthorizeSubscribe(@Client() client, @Subscription() subscription, @Function() done) {
    console.log("Function: @onAuthorizeSubscribe()");
    if (subscription.topic === 'aaaa') {
      return done('wrong topic')
    }
    if (subscription.topic === 'bbb') {
      // overwrites subscription
      subscription.topic = 'foo'
      subscription.qos = 1
    }
    return done(null, subscription);
  }

  //* 
  //*
  //*

  // @onAuthorizeSubscribe()
  // onAuthorizeSubscribe(@Client() client, @Subscription() subscription, @Function() done) {
  //   done(null, subscription.topic === 'aaaa' ? null : sub)
  // }

  @onPublish()
  OnPublish(@Topic() topic, @Packet() packet, @Payload() payload, @Client() client) {
    console.log("Function: @OnPublish()");
  }

  @onClient()
  OnNewClient(@Client() client) {
    console.log("Function: @onClient()");
  }
  
  @onClientReady()
  async onClientReady(@Client() client) {
    console.log("Function: @onClientReady()");
  }

  @onClientDisconnect()
  OnClientDisconnect(@Client() client) {
    console.log("Function: @OnClientDisconnect()");
  }

  @onClientError()
  OnClientError(@Client() client, @Error() error) {
    console.log("Function: @onClientError()");
  }

  @onConnectionError()
  OnConnectionError(@Client() client, @Error() error) {
    console.log("Function: @OnConnectionError()");
  }

  @onKeepLiveTimeout()
  onKeepLiveTimeout(@Client() client) {
    console.log("Function: @onKeepLiveTimeout()");
  }

  // @onPublish()
  // OnPublish(@Topic() topic, @Packet() packet, @Payload() payload, @Client() client) {
  //   console.log("Function: @OnPublish()");
  // }

  @onAck()
  onAck(@Client() client, @Packet() packet) {
    console.log("Function: @onAck()");
  }

  @onSubscribe()
  OnSubscribe(@Subscription() subscription, @Client() client) {
    console.log(subscription)
    console.log("Function: @OnSubscribe()");
  }

  @onUnsubscribe()
  OnUnsubscribe(@Subscription() subscription, @Client() client) {
    console.log("Function: @OnUnsubscribe()");
  }

  @onConnackSent()
  onConnackSent(@Client() client, @Packet() packet) {
    console.log("Function: @onConnackSent()");
  }

  @onClosed()
  onClosed(@Client() client, @Packet() packet) {
    console.log("Function: @onClosed()");
  }

  // @onPublish()
  // async OnPublish(@Topic() topic, @Packet() packet, @Payload() payload, @Client() client) {

  //   //use this method to publish
  //   await this.pigeonService.publish({
  //     topic: "test2", qos: 0, cmd: "publish", payload: "", dup: false, retain: false
  //   });

  // }

  @Process()
  async handle(job: Job<unknown>){
      const receivedPacket : any = job.data //as PublishPacket
      const msgObject = Buffer.from(receivedPacket.payload.data).toString('utf-8')

      const message = {
        type:'text',
        content:{
          text:`已收到您的消息:${msgObject}`,
        }
      }

      const packet : PublishPacket = {
        cmd: 'publish',
        qos:1,
        topic:'chat2',
        retain:false,
        dup:false,
        payload: JSON.stringify(message)
      }

      // const packet : PublishPacket = {
      //   cmd: 'publish',
      //   qos:1,
      //   topic:'chat2',
      //   retain:false,
      //   dup:false,
      //   payload: 'HHHLLLO!SYS'
      // }

      await this.pigeonService.publish(packet)

      //await this.pigeonService.publish(packet)
      
      console.log(msgObject)

      await job.progress(100)
    }
}
